package com.mzj.saas.mservice.propertybill.service;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.mzj.saas.commons.ApiData;
import com.mzj.saas.commons.ConvertUtils;
import com.mzj.saas.commons.KeyWorker;
import com.mzj.saas.commons.ResultBean;
import com.mzj.saas.commons.enums.HouseAuditStatusEnum;
import com.mzj.saas.commons.vo.redis.TokenRedisVo;
import com.mzj.saas.config.sms.SmsConfig;
import com.mzj.saas.mservice.backlog.entity.BacklogItem;
import com.mzj.saas.mservice.backlog.entity.BacklogItemPropertyRentBill;
import com.mzj.saas.mservice.backlog.repository.BacklogItemPropertyRentBillRepository;
import com.mzj.saas.mservice.backlog.repository.BacklogItemRepository;
import com.mzj.saas.mservice.bill.entity.HouseExpenseBillRule;
import com.mzj.saas.mservice.bill.entity.HouseExpenseOther;
import com.mzj.saas.mservice.bill.entity.HouseExpenseRuleRef;
import com.mzj.saas.mservice.bill.repository.ExpenseBillRepository;
import com.mzj.saas.mservice.bill.repository.HouseExpenseBillRuleRepository;
import com.mzj.saas.mservice.bill.repository.HouseExpenseOtherRepository;
import com.mzj.saas.mservice.bill.repository.HouseExpenseRuleRefRepository;
import com.mzj.saas.mservice.bill.vo.CreateBillRequestParamVO;
import com.mzj.saas.mservice.bill.vo.HouseExpenseBillRuleVO;
import com.mzj.saas.mservice.bill.vo.HouseExpenseRuleRefVO;
import com.mzj.saas.mservice.bill.vo.NewProjectVO;
import com.mzj.saas.mservice.community.entity.Community;
import com.mzj.saas.mservice.community.entity.CommunityBuild;
import com.mzj.saas.mservice.community.entity.CommunityBuildUnit;
import com.mzj.saas.mservice.community.repository.CommunityBuildRepository;
import com.mzj.saas.mservice.community.repository.CommunityBuildUnitRepository;
import com.mzj.saas.mservice.community.repository.CommunityRepository;
import com.mzj.saas.mservice.community.service.AppCommunityService;
import com.mzj.saas.mservice.department.service.DepartmentService;
import com.mzj.saas.mservice.eligible.entity.DepartmentEnterpriseTagRef;
import com.mzj.saas.mservice.eligible.entity.DepartmentHierarchy;
import com.mzj.saas.mservice.eligible.repository.DepartmentEnterpriseTagRefRepository;
import com.mzj.saas.mservice.eligible.repository.DepartmentHierarchyRepository;
import com.mzj.saas.mservice.house.entity.House;
import com.mzj.saas.mservice.house.repository.HouseMatchUserRepository;
import com.mzj.saas.mservice.house.repository.HouseRepository;
import com.mzj.saas.mservice.property.entity.*;
import com.mzj.saas.mservice.property.repository.*;
import com.mzj.saas.mservice.propertybill.entity.EstateExpenseBillDetail;
import com.mzj.saas.mservice.propertybill.entity.SaasBacklogItemBill;
import com.mzj.saas.mservice.propertybill.repository.EstateExpenseBillDetailRepository;
import com.mzj.saas.mservice.propertybill.repository.SaasBacklogItemBillRepository;
import com.mzj.saas.mservice.propertybill.vo.CommunitysVO;
import com.mzj.saas.mservice.propertybill.vo.HouseInfoVo;
import com.mzj.saas.mservice.propertybill.vo.UrgingPaymentDTO;
import com.mzj.saas.mservice.propertybill.vo.UrgingPaymentVo;
import com.mzj.saas.mservice.sms.service.SmsService;
import com.mzj.saas.mservice.sys.repository.AppUserRepository;
import com.mzj.saas.redis.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 新的账单费用Service
 */
@Service
public class NewPropertyBillService {
    private static final Logger LOG = LoggerFactory.getLogger(NewPropertyBillService.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private RedisService redisService;
    @Autowired
    private HouseExpenseOtherRepository houseExpenseOtherRepository;
    @Autowired
    private HouseRepository houseRepository;
    @Autowired
    private HouseExpenseRuleRefRepository houseExpenseRuleRefRepository;
    @Autowired
    private HouseExpenseBillRuleRepository houseExpenseBillRuleRepository;
    @Autowired
    private CommunityHouseUserRepository communityHouseUserRepository;
    @Autowired
    private AppCommunityService appCommunityService;
    @Autowired
    private DepartmentHierarchyRepository departmentHierarchyRepository;
    @Autowired
    private CommunityRepository communityRepository;
    @Autowired
    private CommunityBuildRepository communityBuildRepository;
    @Autowired
    private CommunityBuildUnitRepository communityBuildUnitRepository;
    @Autowired
    private DepartmentEnterpriseTagRefRepository departmentEnterpriseTagRefRepository;
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private ExpenseBillRepository expenseBillRepository;
    @Autowired
    private SmsService smsService;
    @Autowired
    private SmsConfig smsConfig;
    @Autowired
    private AppUserRepository appUserRepository;
    @Autowired
    private SaasBacklogItemBillRepository saasBacklogItemBillRepository;
    @Autowired
    private BacklogItemRepository backlogItemRepository;
    @Autowired
    private EstateExpenseBillRepository estateExpenseBillRepository;
    @Autowired
    private MatchUserHouseRepository matchUserHouseRepository;
    @Autowired
    private EstateRentBillRepository estateRentBillRepository;
    @Autowired
    private BacklogItemPropertyRentBillRepository backlogItemPropertyRentBillRepository;
    @Autowired
    private HouseMatchUserRepository houseMatchUserRepository;
    @Autowired
    private EstateExpenseBillDetailRepository estateExpenseBillDetailRepository;
    @Autowired
    private MatchUserRepository matchUserRepository;

    /**
     * 收费项目列表
     *
     * @param accessToken
     * @param pageNumber
     * @param pageSize
     * @param vo          当前公司管理名下的收费项目
     */
    public ResultBean<ApiData<NewProjectVO>> projectList(String accessToken, Integer pageNumber, Integer pageSize, NewProjectVO vo) {
        LOG.info("NewPropertyBillService projectList accessToken={},pageNumber={},pageSize={}", accessToken, pageNumber, pageSize);

        // 校验登录信息
        TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
        if (tokenRedisVo == null) {
            return ResultBean.failedResultOfToken();
        }

        String SQL = " select eo.* from saas_house_expense_other eo left join saas_department d on eo.org_id = d.id  ";
        String count = "select count(1) from saas_house_expense_other eo left join saas_department d on eo.org_id = d.id  ";

        // 政府机构，根据区域标签所对应区域id查看
        Long enterpriseId = tokenRedisVo.getEnterpriseId();
        DepartmentHierarchy hierarchy = departmentHierarchyRepository.findByOrgIdAndStatus(enterpriseId, 1);
        if (hierarchy == null) {
            return ResultBean.failedResultWithMsg("用户所属机构未设置层级架构");
        }
        Long id = hierarchy.getId();
        List<DepartmentEnterpriseTagRef> refs = departmentEnterpriseTagRefRepository.findByDepRefId(id);
        List<Long> enterpriseTagIds = refs.stream().map(DepartmentEnterpriseTagRef::getTagId).distinct().collect(Collectors.toList());// 用户企业标签
        Long areaTagId = hierarchy.getTagId();// 区域标签
        Long areaId = null;
        if (enterpriseTagIds.contains(3L)) {
            areaId = hierarchy.getAreaId();// 区域id
        }
        String areaTag = "";
        if (areaTagId == 1) {
            areaTag = "province_id";
        } else if (areaTagId == 2) {
            areaTag = "city_id";
        } else if (areaTagId == 3) {
            areaTag = "district_id";
        } else if (areaTagId == 4) {
            areaTag = "street_id";
        } else if (areaTagId == 5) {
            areaTag = "community_id";
        }

        List<Object> args = new ArrayList<>();
        StringBuilder where = new StringBuilder(" where 1=1 and eo.status = 1 and eo.type = 2  ");  // status 数据状态：1正常 2已删除

        if (enterpriseTagIds.contains(3L)) {
            where.append(" and (eo.org_id = ? or d." + areaTag + " = ? ) ");
            args.add(enterpriseId);
            args.add(areaId);

        } else {
            where.append(" and eo.org_id = ?  ");
            args.add(enterpriseId);
        }

        if (vo != null) {

            if (StringUtils.isNotBlank(vo.getName())) {
                where.append(" and eo.name like ?  ");
                args.add("%" + vo.getName() + "%");
            }
            if (StringUtils.isNotBlank(vo.getId())) {
                where.append(" and eo.id like ?  ");
                args.add("%" + vo.getId() + "%");
            }

        }

        ApiData<NewProjectVO> apiData = new ApiData<>();

        Long total = jdbcTemplate.queryForObject(count + where, Long.class, args.toArray());
        if (total == 0) {
            return ResultBean.successfulResult(apiData);
        }

        // 查询分页数据
        String offsets = " limit ? offset ?";
        where.append(" ORDER BY ").append(" eo.operator_time desc ").append(" \n").append(offsets);
        args.add(pageSize);
        args.add(pageNumber * pageSize);
        List<NewProjectVO> data = jdbcTemplate.query(SQL + where, new BeanPropertyRowMapper<>(NewProjectVO.class), args.toArray());
        //

        apiData.setTotal(total);
        apiData.setData(data);
        return ResultBean.successfulResult(apiData);
    }

    /**
     * 收费项目-添加更新
     *
     * @param accessToken
     * @param vo
     * @return
     */
    public ResultBean<Object> projectSave(String accessToken, NewProjectVO vo) {
        LOG.info("NewPropertyBillService  projectSave  accessToken={} , vo={}", accessToken, JSON.toJSONString(vo));

        // 校验登录信息
        TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
        if (tokenRedisVo == null) {
            return ResultBean.failedResultOfToken();
        }
        Long orgId = tokenRedisVo.getEnterpriseId();
        if (StringUtils.isBlank(vo.getName())) {
            return ResultBean.failedResultWithMsg("项目名称为空");
        }

        if (StringUtils.isBlank(vo.getId())) {
            // 新增操作
            List<HouseExpenseOther> projectList = houseExpenseOtherRepository.findByNameAndTypeAndOrgIdAndStatus(vo.getName(), 2, orgId, 1);
            // 去重
            if (projectList.size() > 0) {
                return ResultBean.failedResultWithMsg("项目名称已存在");
            }

            HouseExpenseOther houseExpenseOther = new HouseExpenseOther();

            // 租金项目校验收费状
            if (vo.getChargeType() == 8) {
                if (vo.getChargeStatus() == null) {
                    return ResultBean.failedResultWithMsg("收费状态有误！");
                }
            }
            vo.setId("PJ" + KeyWorker.nextId());
            vo.setEnableStatus(0);
            vo.setStatus(1);
            String price = ConvertUtils.yuanToFen(String.valueOf(vo.getPrice()));
            vo.setOperatorId(tokenRedisVo.getId());
            vo.setOperatorTime(new Date());
            vo.setType(2); // 类型：1公租房 2非公租房
            vo.setOrgId(orgId);

            BeanUtils.copyProperties(vo, houseExpenseOther);
            houseExpenseOther.setPrice(Integer.valueOf(price));
            houseExpenseOtherRepository.save(houseExpenseOther);

        } else {
            // 修改操作
            HouseExpenseOther houseExpenseOther = houseExpenseOtherRepository.findById(vo.getId());
            if (houseExpenseOther == null) {
                return ResultBean.failedResultWithMsg("项目不存在");
            }
            // 收费项目不可重复
            if (!vo.getName().equals(houseExpenseOther.getName())) {
                List<HouseExpenseOther> projectList = houseExpenseOtherRepository.findByNameAndTypeAndOrgIdAndStatus(vo.getName(), 2, orgId, 1);
                if (projectList.size() > 0) {
                    return ResultBean.failedResultWithMsg("项目名称已存在");
                }
            }

            houseExpenseOther.setName(vo.getName());
            if (vo.getChargeType() == 9){
                houseExpenseOther.setChargeMode(null);
            }else {
                houseExpenseOther.setChargeMode(vo.getChargeMode());
            }
            houseExpenseOther.setChargeType(vo.getChargeType());
            String price = ConvertUtils.yuanToFen(String.valueOf(vo.getPrice()));
            houseExpenseOther.setPrice(Integer.valueOf(price));
            houseExpenseOther.setUnit(vo.getUnit());
            if (vo.getChargeStatus() != null) {
                houseExpenseOther.setChargeStatus(vo.getChargeStatus());
            }

            houseExpenseOther.setOperatorId(tokenRedisVo.getId());
            houseExpenseOther.setOperatorTime(new Date());

            houseExpenseOtherRepository.save(houseExpenseOther);

        }
        return ResultBean.successfulResult(null);
    }

    /**
     * 收费项目-删除
     *
     * @param accessToken
     * @param id          修改收费项目状态为删除
     */
    public ResultBean<Object> projectDelete(String accessToken, String id) {
        LOG.info("NewPropertyBillService  projectDelete  accessToken={} , id={}", accessToken, id);

        HouseExpenseOther entity = houseExpenseOtherRepository.findById(id);
        if (entity == null) {
            return ResultBean.failedResultWithMsg("项目不存在");
        }

        entity.setStatus(2);// status 数据状态：1正常 2已删除
        houseExpenseOtherRepository.save(entity);

        return ResultBean.successfulResult(null);
    }

    /**
     * 账单生成
     *
     * @param accessToken
     * @param createBillRequestParamVO
     * @return 生成账单 根据对应账单规则生成账单  过滤公租房  同一时间段内相同账单不可生成 押金账单唯一
     */
    public ResultBean<Object> createBill(String accessToken, CreateBillRequestParamVO createBillRequestParamVO) {
        LOG.info("NewPropertyBillService  createBill  accessToken={} ", accessToken);

        TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
        if (tokenRedisVo == null) {
            return ResultBean.failedResultOfToken();
        }


        // 账单规则
        HouseExpenseBillRuleVO ruleVO = createBillRequestParamVO.getHouseExpenseBillRuleVO();
        // 账单规则与小区、房屋关系
        List<HouseExpenseRuleRefVO> ruleRefVO = createBillRequestParamVO.getHouseExpenseRuleRefVOS();
        Integer scope = ruleVO.getScope();
        // 账单范围选择[ 1物业、2小区、3楼栋、4单元、5房号]
        switch (scope) {
            case 1:// 1物业
                List<Long> housePropertyIds = ruleRefVO.stream().map(HouseExpenseRuleRefVO::getHousePropertyId).collect(Collectors.toList());
                List<House> houseList = houseRepository.findByHousePropertyIdIn(housePropertyIds);
                List<HouseExpenseRuleRefVO> refs = new ArrayList<>();
                for (House house : houseList) {
                    HouseExpenseRuleRefVO ref = new HouseExpenseRuleRefVO();
                    ref.setHouseNature(house.getHouseNature());
                    ref.setCommunityId(house.getResidenceCommunityId());
                    ref.setBuildingNum(house.getBuildingNum());
                    ref.setUnit(house.getUnit());
                    ref.setHouseId(house.getId());
                    refs.add(ref);
                }
                ruleRefVO = refs;
                break;
            case 2:// 小区
                List<String> residenceCommunityIds = ruleRefVO.stream().map(HouseExpenseRuleRefVO::getCommunityId).collect(Collectors.toList());
                List<House> houseList1 = houseRepository.findByResidenceCommunityIdIn(residenceCommunityIds);
                List<HouseExpenseRuleRefVO> refs1 = new ArrayList<>();
                for (House house : houseList1) {
                    HouseExpenseRuleRefVO ref = new HouseExpenseRuleRefVO();
                    ref.setHouseNature(house.getHouseNature());
                    ref.setCommunityId(house.getResidenceCommunityId());
                    ref.setBuildingNum(house.getBuildingNum());
                    ref.setUnit(house.getUnit());
                    ref.setHouseId(house.getId());
                    refs1.add(ref);
                }
                ruleRefVO = refs1;
                break;
            case 3:// 楼栋
                List<House> houseList2 = new ArrayList<>();
                for (HouseExpenseRuleRefVO ref : ruleRefVO) {
                    String residenceCommunityId = ref.getCommunityId();
                    Long buildingNum = ref.getBuildingNum();
                    houseList2.addAll(houseRepository.findByResidenceCommunityIdAndBuildingNum(residenceCommunityId, buildingNum));
                }

                List<HouseExpenseRuleRefVO> refs2 = new ArrayList<>();
                for (House house : houseList2) {
                    HouseExpenseRuleRefVO ref = new HouseExpenseRuleRefVO();
                    ref.setHouseNature(house.getHouseNature());
                    ref.setCommunityId(house.getResidenceCommunityId());
                    ref.setBuildingNum(house.getBuildingNum());
                    ref.setUnit(house.getUnit());
                    ref.setHouseId(house.getId());
                    refs2.add(ref);
                }
                ruleRefVO = refs2;
                break;
            case 4:// 单元
                List<House> houseList3 = new ArrayList<>();
                for (HouseExpenseRuleRefVO ref : ruleRefVO) {
                    String residenceCommunityId = ref.getCommunityId();
                    Long buildingNum = ref.getBuildingNum();
                    Long unit = ref.getUnit();
                    houseList3.addAll(houseRepository.findByResidenceCommunityIdAndBuildingNumAndUnit(residenceCommunityId, buildingNum, unit));
                }
                List<HouseExpenseRuleRefVO> refs3 = new ArrayList<>();
                for (House house : houseList3) {
                    HouseExpenseRuleRefVO ref = new HouseExpenseRuleRefVO();
                    ref.setHouseNature(house.getHouseNature());
                    ref.setCommunityId(house.getResidenceCommunityId());
                    ref.setBuildingNum(house.getBuildingNum());
                    ref.setUnit(house.getUnit());
                    ref.setHouseId(house.getId());
                    refs3.add(ref);
                }
                ruleRefVO = refs3;
                break;
        }
        if (ruleVO.getViolateStatus() == 1) {
            if (ruleVO.getViolateRatio() == null || StringUtils.isEmpty(ruleVO.getViolateRatio().toPlainString())) {
                return ResultBean.failedResultOfParamWithMsg("违约金比例有误");
            }
        }
        // 缴费截至规则 1前 2后
        Integer flag = ruleVO.getFlag();
        Integer day = ruleVO.getDay();

        if (day == null) {
            return ResultBean.failedResultOfParamWithMsg("请完善缴费截止日期");
        }

        Date startTimes = ruleVO.getStartTime();
        Integer dateFlag = ruleVO.getDateFlag();// 时间标志：1开始时间 2结束时间
        if (dateFlag != null && dateFlag.equals(2)) {
            startTimes = ruleVO.getEndTime();

        }
        // 账单缴费截至时间
        Date closeTime = null;

        if (flag.equals(1)) {  // 1前 2后
            Calendar cal = Calendar.getInstance();
            cal.setTime(startTimes);
            cal.add(Calendar.DAY_OF_MONTH, -day);
            closeTime = cal.getTime();
        } else {
            Calendar cal = Calendar.getInstance();
            cal.setTime(startTimes);
            cal.add(Calendar.DAY_OF_MONTH, day);
            closeTime = cal.getTime();
        }

        // 缴费截至日期
        ruleVO.setCloseTime(closeTime);
        ruleVO.setType(2); // 类型：1公租房 2非公租房

        // 物业租押金，过滤掉公租房
        if (ruleVO.getChargeType() == 8 || ruleVO.getChargeType() == 9) {
            List<HouseExpenseRuleRefVO> refs = new ArrayList<>();
            for (HouseExpenseRuleRefVO ref : ruleRefVO) {
                if (!ref.getHouseNature().equals(1)) {
                    refs.add(ref);
                }
            }
            ruleRefVO = refs;
        }

        List<String> failRoomNumberList = new ArrayList<>(); // 账单已存在的房号
        List<String> noUserRoomNumberList = new ArrayList<>(); // 无承租人的房号

        // 账单规则非押金
        if (!ruleVO.getChargeType().equals(9)) {
            // 验证账单周期
            for (HouseExpenseRuleRefVO houseExpenseRuleRefVO : ruleRefVO) {
                List<HouseExpenseRuleRef> existHouseExpenseRule = houseExpenseRuleRefRepository.findByHouseId(houseExpenseRuleRefVO.getHouseId());
                for (HouseExpenseRuleRef houseExpenseRuleRef : existHouseExpenseRule) {
                    HouseExpenseBillRule houseExpenseBillRule = houseExpenseBillRuleRepository.findById(houseExpenseRuleRef.getRuleId());
                    // 时间段不能有交集
                    if (houseExpenseBillRule.getChargeType().equals(ruleVO.getChargeType())) {
                        if ((ruleVO.getStartTime().getTime() < houseExpenseBillRule.getStartTime().getTime() && ruleVO.getEndTime().getTime() >= houseExpenseBillRule.getStartTime().getTime())
                                || (ruleVO.getStartTime().getTime() >= houseExpenseBillRule.getStartTime().getTime() && ruleVO.getEndTime().getTime() <= houseExpenseBillRule.getEndTime().getTime())
                                || (ruleVO.getStartTime().getTime() <= houseExpenseBillRule.getEndTime().getTime() && ruleVO.getEndTime().getTime() > houseExpenseBillRule.getEndTime().getTime())) {
                            // return ResultBean.failedResultWithMsg("周期内账单已存在");
                            House house = houseRepository.findById(houseExpenseRuleRefVO.getHouseId()).get();
                            failRoomNumberList.add(house.getRoomNumber());
                        }
                    }
                }
            }

            // 验证是否有承租人
        /*    for (HouseExpenseRuleRefVO houseExpenseRuleRefVO : ruleRefVO) {
                List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseExpenseRuleRefVO.getHouseId(), 1, 1);
                if(communityHouseUserList.size() == 0){
                    LOG.warn("未找到租客信息 houseId={}", houseExpenseRuleRefVO.getHouseId());
                    House house = houseRepository.findById(houseExpenseRuleRefVO.getHouseId()).get();
                    noUserRoomNumberList.add(house.getRoomNumber());
                }
            }*/

        } else {  // 押金
            // 验证账单存在
            for (HouseExpenseRuleRefVO houseExpenseRuleRefVO : ruleRefVO) {
                List<HouseExpenseRuleRef> existHouseExpenseRule = houseExpenseRuleRefRepository.findByHouseId(houseExpenseRuleRefVO.getHouseId());
                for (HouseExpenseRuleRef houseExpenseRuleRef : existHouseExpenseRule) {
                    HouseExpenseBillRule houseExpenseBillRule = houseExpenseBillRuleRepository.findById(houseExpenseRuleRef.getRuleId());
                    if (houseExpenseBillRule.getChargeType().equals(ruleVO.getChargeType())) {
                        // return ResultBean.failedResultWithMsg("押金账单已存在");
                        House house = houseRepository.findById(houseExpenseRuleRefVO.getHouseId()).get();
                        failRoomNumberList.add(house.getRoomNumber());
                    }
                }
            }

            // 验证是否有承租人
      /*      for (HouseExpenseRuleRefVO houseExpenseRuleRefVO : ruleRefVO) {
                List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseExpenseRuleRefVO.getHouseId(), 1, 1);
                if(communityHouseUserList.size() == 0){
                    LOG.warn("未找到租客信息 houseId={}", houseExpenseRuleRefVO.getHouseId());
                    House house = houseRepository.findById(houseExpenseRuleRefVO.getHouseId()).get();
                    noUserRoomNumberList.add(house.getRoomNumber());
                }
            }*/

        }

        // 返回失败房号
        if (failRoomNumberList.size() > 0) {
            return ResultBean.failedResultWithMsg(failRoomNumberList.toString() + "：账单已存在，无法生成账单");
        }
    /*    if(noUserRoomNumberList.size() > 0){
            return ResultBean.failedResultWithMsg(noUserRoomNumberList.toString() + "：无承租人，无法生成账单");
        }*/

        // 无房屋则不生成
        if (ruleRefVO.size() == 0) {
            return ResultBean.failedResultWithMsg("无房屋生成！");
        }

        // 违约金是否生成状态 ： 0不生成 1生成
        Integer violateStatus = ruleVO.getViolateStatus();
        if (violateStatus == null) {
            return ResultBean.failedResultOfParamWithMsg("违约金状态有误");
        } else if (violateStatus == 1) {
            if (Double.parseDouble(ruleVO.getViolateRatio().toPlainString()) <= 0) {
                return ResultBean.failedResultOfParamWithMsg("违约金比例不得小于0%");
            }
        }
        // 生成账单
        ruleVO.setId("ZD" + KeyWorker.nextId());
        ruleVO.setNumber(ruleRefVO.size());
        ruleVO.setOperatorId(tokenRedisVo.getId());
        ruleVO.setCreateTime(new Date());
        HouseExpenseBillRule houseExpenseBillRule = new HouseExpenseBillRule();
        BeanUtils.copyProperties(ruleVO, houseExpenseBillRule);
        houseExpenseBillRule.setCollectionOrg(tokenRedisVo.getEnterpriseId());
        houseExpenseBillRule.setOrgId(ruleVO.getOrgId());
        houseExpenseBillRule.setCompanyName(ruleVO.getCompanyName());// 单位名称
        houseExpenseBillRule.setStatus(0);// 0正常 1终止
        // 立即生成状态：0未生成 1已生成
        houseExpenseBillRule.setCreateStatus(0);
        if (ruleVO.getViolateStatus() == 1) {
            houseExpenseBillRule.setViolateRatio(ruleVO.getViolateRatio().toPlainString());
        }
        HouseExpenseBillRule save = houseExpenseBillRuleRepository.save(houseExpenseBillRule);
        if (save != null) {
            List<HouseExpenseRuleRef> ruleRefList = new ArrayList<>();
            ruleRefVO.forEach(h -> {
                HouseExpenseRuleRef houseExpenseRuleRef = new HouseExpenseRuleRef();
                BeanUtils.copyProperties(h, houseExpenseRuleRef);
                houseExpenseRuleRef.setRuleId(save.getId());
                houseExpenseRuleRef.setAuditStatus(HouseAuditStatusEnum.NO_AUDIT.getValue());
                ruleRefList.add(houseExpenseRuleRef);
            });

            houseExpenseRuleRefRepository.saveAll(ruleRefList);
        }

        return ResultBean.successfulResult(null);
    }

    // 账单生成-编辑账单
    public ResultBean<Object> updateBill(String accessToken, CreateBillRequestParamVO createBillRequestParamVO) {
        LOG.info("NewPropertyBillService  updateBill  accessToken={} ", accessToken);

        TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
        if (tokenRedisVo == null) {
            return ResultBean.failedResultOfToken();
        }

        HouseExpenseBillRuleVO ruleVO = createBillRequestParamVO.getHouseExpenseBillRuleVO();
        List<HouseExpenseRuleRefVO> ruleRefVO = createBillRequestParamVO.getHouseExpenseRuleRefVOS();


        Date startTime = ruleVO.getStartTime();
        Date endTime = ruleVO.getEndTime();
        if (startTime.getTime() > endTime.getTime()) {
            return ResultBean.failedResultWithMsg("账单结束时间不能小于开始时间");
        }

        if (StringUtils.isBlank(ruleVO.getId())) {
            return ResultBean.failedResultWithMsg("账单id为空");
        }

        Integer scope = ruleVO.getScope();
        // 账单范围选择[ 1物业、2小区、3楼栋、4单元、5房号]
        switch (scope) {
            case 1:
                List<Long> housePropertyIds = ruleRefVO.stream().map(HouseExpenseRuleRefVO::getHousePropertyId).collect(Collectors.toList());
                List<House> houseList = houseRepository.findByHousePropertyIdIn(housePropertyIds);
                List<HouseExpenseRuleRefVO> refs = new ArrayList<>();
                for (House house : houseList) {
                    HouseExpenseRuleRefVO ref = new HouseExpenseRuleRefVO();
                    ref.setHouseNature(house.getHouseNature());
                    ref.setCommunityId(house.getResidenceCommunityId());
                    ref.setBuildingNum(house.getBuildingNum());
                    ref.setUnit(house.getUnit());
                    ref.setHouseId(house.getId());
                    refs.add(ref);
                }
                ruleRefVO = refs;
                break;
            case 2:
                List<String> residenceCommunityIds = ruleRefVO.stream().map(HouseExpenseRuleRefVO::getCommunityId).collect(Collectors.toList());
                List<House> houseList1 = houseRepository.findByResidenceCommunityIdIn(residenceCommunityIds);
                List<HouseExpenseRuleRefVO> refs1 = new ArrayList<>();
                for (House house : houseList1) {
                    HouseExpenseRuleRefVO ref = new HouseExpenseRuleRefVO();
                    ref.setHouseNature(house.getHouseNature());
                    ref.setCommunityId(house.getResidenceCommunityId());
                    ref.setBuildingNum(house.getBuildingNum());
                    ref.setUnit(house.getUnit());
                    ref.setHouseId(house.getId());
                    refs1.add(ref);
                }
                ruleRefVO = refs1;
                break;
            case 3:
                List<House> houseList2 = new ArrayList<>();
                for (HouseExpenseRuleRefVO ref : ruleRefVO) {
                    String residenceCommunityId = ref.getCommunityId();
                    Long buildingNum = ref.getBuildingNum();
                    houseList2.addAll(houseRepository.findByResidenceCommunityIdAndBuildingNum(residenceCommunityId, buildingNum));
                }

                List<HouseExpenseRuleRefVO> refs2 = new ArrayList<>();
                for (House house : houseList2) {
                    HouseExpenseRuleRefVO ref = new HouseExpenseRuleRefVO();
                    ref.setHouseNature(house.getHouseNature());
                    ref.setCommunityId(house.getResidenceCommunityId());
                    ref.setBuildingNum(house.getBuildingNum());
                    ref.setUnit(house.getUnit());
                    ref.setHouseId(house.getId());
                    refs2.add(ref);
                }
                ruleRefVO = refs2;
                break;
            case 4:
                List<House> houseList3 = new ArrayList<>();
                for (HouseExpenseRuleRefVO ref : ruleRefVO) {
                    String residenceCommunityId = ref.getCommunityId();
                    Long buildingNum = ref.getBuildingNum();
                    Long unit = ref.getUnit();
                    houseList3.addAll(houseRepository.findByResidenceCommunityIdAndBuildingNumAndUnit(residenceCommunityId, buildingNum, unit));
                }
                List<HouseExpenseRuleRefVO> refs3 = new ArrayList<>();
                for (House house : houseList3) {
                    HouseExpenseRuleRefVO ref = new HouseExpenseRuleRefVO();
                    ref.setHouseNature(house.getHouseNature());
                    ref.setCommunityId(house.getResidenceCommunityId());
                    ref.setBuildingNum(house.getBuildingNum());
                    ref.setUnit(house.getUnit());
                    ref.setHouseId(house.getId());
                    refs3.add(ref);
                }
                ruleRefVO = refs3;
                break;
        }

        Integer flag = ruleVO.getFlag();
        Integer day = ruleVO.getDay();
        Date startTimes = ruleVO.getStartTime();
        Integer dateFlag = ruleVO.getDateFlag();// 时间标志：1开始时间 2结束时间
        if (dateFlag != null && dateFlag.equals(2)) {
            startTimes = ruleVO.getEndTime();

        }
        Date closeTime = null;

        if (flag.equals(1)) {  // 1前 2后
            Calendar cal = Calendar.getInstance();
            cal.setTime(startTimes);
            cal.add(Calendar.DAY_OF_MONTH, -day);
            closeTime = cal.getTime();
        } else {
            Calendar cal = Calendar.getInstance();
            cal.setTime(startTimes);
            cal.add(Calendar.DAY_OF_MONTH, day);
            closeTime = cal.getTime();
        }

        ruleVO.setCloseTime(closeTime);
        ruleVO.setType(2); // 类型：1公租房 2非公租房

        // 物业租押金，过滤掉公租房
        if (ruleVO.getChargeType() == 8 || ruleVO.getChargeType() == 9) {
            List<HouseExpenseRuleRefVO> refs = new ArrayList<>();
            for (HouseExpenseRuleRefVO ref : ruleRefVO) {
                if (!ref.getHouseNature().equals(1)) {
                    refs.add(ref);
                }
            }
            ruleRefVO = refs;
        }

        if (ruleVO.getViolateStatus() == 1) {
            if (ruleVO.getViolateRatio() == null || StringUtils.isEmpty(ruleVO.getViolateRatio().toPlainString())) {
                return ResultBean.failedResultOfParamWithMsg("违约金比例有误");
            }
        }

        List<String> failRoomNumberList = new ArrayList<>(); // 账单已存在的房号
        List<String> noUserRoomNumberList = new ArrayList<>(); // 无承租人的房号

        if (!ruleVO.getChargeType().equals(9)) {
            // 验证账单周期
            for (HouseExpenseRuleRefVO houseExpenseRuleRefVO : ruleRefVO) {
                List<HouseExpenseRuleRef> existHouseExpenseRule = houseExpenseRuleRefRepository.findByHouseId(houseExpenseRuleRefVO.getHouseId());
                for (HouseExpenseRuleRef houseExpenseRuleRef : existHouseExpenseRule) {
                    if (houseExpenseRuleRef.getRuleId().equals(ruleVO.getId())) {
                        continue;
                    }
                    HouseExpenseBillRule houseExpenseBillRule = houseExpenseBillRuleRepository.findById(houseExpenseRuleRef.getRuleId());
                    // 时间段不能有交集
                    if (houseExpenseBillRule.getChargeType().equals(ruleVO.getChargeType())) {
                        if ((ruleVO.getStartTime().getTime() < houseExpenseBillRule.getStartTime().getTime() && ruleVO.getEndTime().getTime() >= houseExpenseBillRule.getStartTime().getTime())
                                || (ruleVO.getStartTime().getTime() >= houseExpenseBillRule.getStartTime().getTime() && ruleVO.getEndTime().getTime() <= houseExpenseBillRule.getEndTime().getTime())
                                || (ruleVO.getStartTime().getTime() <= houseExpenseBillRule.getEndTime().getTime() && ruleVO.getEndTime().getTime() > houseExpenseBillRule.getEndTime().getTime())) {
                            // return ResultBean.failedResultWithMsg("周期内账单已存在");
                            House house = houseRepository.findById(houseExpenseRuleRefVO.getHouseId()).get();
                            failRoomNumberList.add(house.getRoomNumber());
                        }
                    }
                }
            }

            // 验证是否有承租人
        /*    for (HouseExpenseRuleRefVO houseExpenseRuleRefVO : ruleRefVO) {
                List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseExpenseRuleRefVO.getHouseId(), 1, 1);
                if(communityHouseUserList.size() == 0){
                    LOG.warn("未找到租客信息 houseId={}", houseExpenseRuleRefVO.getHouseId());
                    House house = houseRepository.findById(houseExpenseRuleRefVO.getHouseId()).get();
                    noUserRoomNumberList.add(house.getRoomNumber());
                }
            }*/

        } else {  // 押金
            // 验证账单存在
            for (HouseExpenseRuleRefVO houseExpenseRuleRefVO : ruleRefVO) {
                List<HouseExpenseRuleRef> existHouseExpenseRule = houseExpenseRuleRefRepository.findByHouseId(houseExpenseRuleRefVO.getHouseId());
                for (HouseExpenseRuleRef houseExpenseRuleRef : existHouseExpenseRule) {
                    if (houseExpenseRuleRef.getRuleId().equals(ruleVO.getId())) {
                        continue;
                    }
                    HouseExpenseBillRule houseExpenseBillRule = houseExpenseBillRuleRepository.findById(houseExpenseRuleRef.getRuleId());
                    if (houseExpenseBillRule.getChargeType().equals(ruleVO.getChargeType())) {
                        // return ResultBean.failedResultWithMsg("押金账单已存在");
                        House house = houseRepository.findById(houseExpenseRuleRefVO.getHouseId()).get();
                        failRoomNumberList.add(house.getRoomNumber());
                    }
                }
            }

            // 验证是否有承租人
      /*      for (HouseExpenseRuleRefVO houseExpenseRuleRefVO : ruleRefVO) {
                List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseExpenseRuleRefVO.getHouseId(), 1, 1);
                if(communityHouseUserList.size() == 0){
                    LOG.warn("未找到租客信息 houseId={}", houseExpenseRuleRefVO.getHouseId());
                    House house = houseRepository.findById(houseExpenseRuleRefVO.getHouseId()).get();
                    noUserRoomNumberList.add(house.getRoomNumber());
                }
            }*/

        }

        // 返回失败房号
        if (failRoomNumberList.size() > 0) {
            return ResultBean.failedResultWithMsg(failRoomNumberList.toString() + "：账单已存在，无法生成账单");
        }
    /*    if(noUserRoomNumberList.size() > 0){
            return ResultBean.failedResultWithMsg(noUserRoomNumberList.toString() + "：无承租人，无法生成账单");
        }*/

        // 无房屋则不生成
        if (ruleRefVO.size() == 0) {
            return ResultBean.failedResultWithMsg("无房屋生成！");
        }

        houseExpenseBillRuleRepository.deleteById(ruleVO.getId());
        houseExpenseRuleRefRepository.deleteByRuleId(ruleVO.getId());

        // 生成账单
        ruleVO.setId("ZD" + KeyWorker.nextId());
        ruleVO.setNumber(ruleRefVO.size());
        ruleVO.setOperatorId(tokenRedisVo.getId());
        ruleVO.setCreateTime(new Date());
        HouseExpenseBillRule houseExpenseBillRule = new HouseExpenseBillRule();
        BeanUtils.copyProperties(ruleVO, houseExpenseBillRule);
        houseExpenseBillRule.setCollectionOrg(tokenRedisVo.getEnterpriseId());
        houseExpenseBillRule.setOrgId(ruleVO.getOrgId());
        houseExpenseBillRule.setStatus(0);// 0正常 1终止
        // 立即生成状态：0未生成 1已生成
        houseExpenseBillRule.setCreateStatus(0);
        if (ruleVO.getViolateStatus() == 1)
            houseExpenseBillRule.setViolateRatio(ruleVO.getViolateRatio().toPlainString());
        HouseExpenseBillRule save = houseExpenseBillRuleRepository.save(houseExpenseBillRule);
        if (save != null) {
            List<HouseExpenseRuleRef> ruleRefList = new ArrayList<>();
            ruleRefVO.forEach(h -> {
                HouseExpenseRuleRef houseExpenseRuleRef = new HouseExpenseRuleRef();
                BeanUtils.copyProperties(h, houseExpenseRuleRef);
                houseExpenseRuleRef.setRuleId(save.getId());
                houseExpenseRuleRef.setAuditStatus(HouseAuditStatusEnum.NO_AUDIT.getValue());
                ruleRefList.add(houseExpenseRuleRef);
            });

            houseExpenseRuleRefRepository.saveAll(ruleRefList);
        }

        return ResultBean.successfulResult(null);
    }

    // 账单生成-删除账单
    public ResultBean<Object> deleteBill(String accessToken, String id) {
        LOG.info("NewPropertyBillService deleteBill accessToken={},id={}", accessToken, id);

        if (StringUtils.isBlank(id)) {
            return ResultBean.failedResultWithMsg("账单id为空");
        }

        houseExpenseBillRuleRepository.deleteById(id);
        houseExpenseRuleRefRepository.deleteByRuleId(id);

        return ResultBean.successfulResult(null);
    }

    // 账单生成-账单详情
    public ResultBean<Object> billInfo(String accessToken, String id) {
        LOG.info("NewPropertyBillService  billInfo  accessToken={} ,id={}", accessToken, id);

        if (StringUtils.isBlank(id)) {
            return ResultBean.failedResultWithMsg("账单id为空");
        }

        HouseExpenseBillRule rule = houseExpenseBillRuleRepository.findById(id);
        if (rule == null) {
            return ResultBean.failedResultWithMsg("账单不存在");
        }

        HouseExpenseBillRuleVO vo = new HouseExpenseBillRuleVO();
        BeanUtils.copyProperties(rule, vo);
        if (rule.getViolateRatio() != null) {
            vo.setViolateRatio(new BigDecimal(rule.getViolateRatio()));
        }
        HouseExpenseOther houseExpenseOther = houseExpenseOtherRepository.findById(vo.getExpenseId());
        if (houseExpenseOther != null) {
            vo.setExpenseName(houseExpenseOther.getName());
        }

        DepartmentHierarchy departmentHierarchy = departmentHierarchyRepository.findByOrgId(vo.getCollectionOrg());
        if (departmentHierarchy != null) {
            vo.setCollectionOrgName(departmentHierarchy.getName());
        }

        List<HouseExpenseRuleRef> ref = houseExpenseRuleRefRepository.findByRuleId(vo.getId());
        List<HouseExpenseRuleRefVO> refVO = new ArrayList<>();
        ref.forEach(r -> {
            HouseExpenseRuleRefVO v = new HouseExpenseRuleRefVO();
            BeanUtils.copyProperties(r, v);
            refVO.add(v);
        });

        vo.setHouseExpenseRuleRefVOList(refVO);
        List<String> houseIds = refVO.stream().map(HouseExpenseRuleRefVO::getHouseId).collect(Collectors.toList());

        List<Map<String, Object>> resultList = new ArrayList<>();// 原始账单记录选中数据
        List<House> houseList = houseRepository.findByIdIn(houseIds);

        switch (vo.getScope()) { // 账单范围选择[ 1物业、2小区、3楼栋、4单元、5房号]

            case 1:
                Map<Long, Object> tempMap = new HashMap<>();
                for (House house : houseList) {
                    Map<String, Object> map = new HashMap<>();
                    if (tempMap.containsKey(house.getHousePropertyId())) {
                        continue;
                    }
                    map.put("housePropertyId", house.getHousePropertyId());
                    DepartmentHierarchy h = departmentHierarchyRepository.findByOrgId(house.getHousePropertyId());
                    map.put("housePropertyName", h.getName());
                    resultList.add(map);
                    tempMap.put(house.getHousePropertyId(), 1);
                }
                break;
            case 2:
                Map<String, Object> tempMap1 = new HashMap<>();
                for (House house : houseList) {
                    Map<String, Object> map = new HashMap<>();
                    if (tempMap1.containsKey(house.getResidenceCommunityId())) {
                        continue;
                    }
                    map.put("communityId", house.getResidenceCommunityId());
                    Community community = communityRepository.findById(house.getResidenceCommunityId()).get();
                    map.put("communityName", community.getName());
                    resultList.add(map);
                    tempMap1.put(house.getResidenceCommunityId(), 1);
                }
                break;
            case 3:
                Map<String, Object> tempMap2 = new HashMap<>();
                for (House house : houseList) {
                    Map<String, Object> map = new HashMap<>();
                    if (tempMap2.containsKey(house.getResidenceCommunityId() + house.getBuildingNum())) {
                        continue;
                    }
                    map.put("communityId", house.getResidenceCommunityId());
                    Community community = communityRepository.findById(house.getResidenceCommunityId()).get();
                    map.put("communityName", community.getName());

                    map.put("buildingNum", house.getBuildingNum());
                    CommunityBuild build = communityBuildRepository.findById(house.getBuildingNum()).get();
                    map.put("buildingNumName", build.getName());

                    resultList.add(map);
                    tempMap2.put(house.getResidenceCommunityId() + house.getBuildingNum(), 1);
                }
                break;
            case 4:
                Map<String, Object> tempMap3 = new HashMap<>();
                for (House house : houseList) {
                    Map<String, Object> map = new HashMap<>();
                    if (tempMap3.containsKey(house.getResidenceCommunityId() + house.getBuildingNum() + house.getUnit())) {
                        continue;
                    }
                    map.put("communityId", house.getResidenceCommunityId());
                    Community community = communityRepository.findById(house.getResidenceCommunityId()).get();
                    map.put("communityName", community.getName());

                    map.put("buildingNum", house.getBuildingNum());
                    CommunityBuild build = communityBuildRepository.findById(house.getBuildingNum()).get();
                    map.put("buildingNumName", build.getName());

                    map.put("unit", house.getUnit());
                    CommunityBuildUnit unit = communityBuildUnitRepository.findById(house.getUnit()).get();
                    map.put("unitName", unit.getName());

                    resultList.add(map);
                    tempMap3.put(house.getResidenceCommunityId() + house.getBuildingNum() + house.getUnit(), 1);
                }
                break;
            case 5:
                for (House house : houseList) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("communityId", house.getResidenceCommunityId());
                    Community community = communityRepository.findById(house.getResidenceCommunityId()).get();
                    map.put("communityName", community.getName());

                    map.put("buildingNum", house.getBuildingNum());
                    CommunityBuild build = communityBuildRepository.findById(house.getBuildingNum()).get();
                    map.put("buildingNumName", build.getName());

                    map.put("unit", house.getUnit());
                    CommunityBuildUnit unit = communityBuildUnitRepository.findById(house.getUnit()).get();
                    map.put("unitName", unit.getName());
                    map.put("houseId", house.getId());
                    map.put("roomNumber", house.getRoomNumber());
                    map.put("houseNature", house.getHouseNature());
                    if (vo.getChargeType() == 8 || vo.getChargeType() == 9) {  // 收费项目(1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金)
                        if (house.getHouseNature().equals(1)) {
                            continue;  // 过滤掉公租房
                        }
                    }
                    resultList.add(map);
                }
                break;

        }
        String sql = "SELECT   h.id,\n" +
                "IFNULL(( select concat (date_format( co.start_time, '%Y-%m-%d') ,'至', date_format( co.ent_time, '%Y-%m-%d') ) from  saas_house_contract co where  co.status <>0 and  co.house_id = h.id GROUP BY co.operation_time DESC LIMIT 1 ) , \n" +
                "( select  concat (date_format( ho.start_date, '%Y-%m-%d') ,'至', date_format( ho.end_date, '%Y-%m-%d') ) from  m_match_user_house ho \n" +
                "where  ho.house_id=h.id) )as term, \n" +
                "IFNULL( ( select co.pay_type from  saas_house_contract co where  co.status <>0 and  co.house_id = h.id GROUP BY co.operation_time DESC LIMIT 1 ),   \n" +
                "( select  ho.charge_mode from  m_match_user_house ho \n" +
                "where  ho.house_id=h.id))as payType \n" +
                "FROM saas_house h       where 1=1 and h.id=? ";

        for (House house : houseList) {
            Map<String, Object> map = new HashMap<>();
            map.put("communityId", house.getResidenceCommunityId());
            Community community = communityRepository.findById(house.getResidenceCommunityId()).get();
            map.put("communityName", community.getName());

            map.put("buildingNum", house.getBuildingNum());
            CommunityBuild build = communityBuildRepository.findById(house.getBuildingNum()).get();
            map.put("buildingNumName", build.getName());

            map.put("unit", house.getUnit());
            CommunityBuildUnit unit = communityBuildUnitRepository.findById(house.getUnit()).get();
            map.put("unitName", unit.getName());
            map.put("houseId", house.getId());
            map.put("roomNumber", house.getRoomNumber());
            map.put("houseNature", house.getHouseNature());

            List<HouseInfoVo> query = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(HouseInfoVo.class), house.getId());
            if (query != null && query.size() > 0) {
                map.put("payType", query.get(0).getPayType());// 缴费方式
                map.put("term", query.get(0).getTerm());// 合同期限
            }


            resultList.add(map);
        }
        vo.setResultList(resultList);

        return ResultBean.successfulResult(vo);

    }

    // 账单生成-列表展示
    public ResultBean<Object> createBillList(String accessToken, Integer pageNumber, Integer pageSize, String id, String community) {
        LOG.info("NewPropertyBillService  createBillList  accessToken={} ", accessToken);

        return null;
    }

    /**
     * 查询收费项目
     *
     * @param accessToken
     * @return
     */
    public ResultBean<Object> findByProjectList(String accessToken) {
        LOG.info("NewPropertyBillService  findByProjectList  accessToken={} ", accessToken);

        List<NewProjectVO> list = this.projectList(accessToken, 0, 1000, null).getResultData().getData();

        return ResultBean.successfulResult(list);
    }

    // 查询账单范围下的房源数据 [scope: 账单范围选择[ 1物业、2小区、3楼栋、4单元、5房号]]  , chargeType :收费项目(1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金)
    public ResultBean<Object> findByHouseInfo(String accessToken, Integer pageNumber, Integer pageSize, Integer scope, Integer chargeType, String communityId, String buildingNum, String unitId, String roomNumber) {
        LOG.info("NewPropertyBillService  findByHouseInfo  accessToken={} ", accessToken);

        List<Map<String, Object>> list = appCommunityService.findCommunity(accessToken).getResultData();
        List<String> communityIds = new ArrayList<>();
        if (list != null && !list.isEmpty()) {
            communityIds = list.stream().map(map -> {
                String comId = map.get("communityId").toString();
                return comId;
            }).collect(Collectors.toList());
        }
        if (communityIds.size() == 0) {
            return ResultBean.successfulResult(null);
        }

        List<Map<String, Object>> resultList = new ArrayList<>();

        List<House> houseList = new ArrayList<>();
        if (StringUtils.isBlank(communityId)) {
            houseList = houseRepository.findByResidenceCommunityIdIn(communityIds);
        } else {
            houseList = houseRepository.findByResidenceCommunityId(communityId);
            if (StringUtils.isNotBlank(buildingNum)) {
                houseList = houseRepository.findByResidenceCommunityIdAndBuildingNum(communityId, Long.valueOf(buildingNum));
                if (StringUtils.isNotBlank(unitId)) {
                    houseList = houseRepository.findByResidenceCommunityIdAndBuildingNumAndUnit(communityId, Long.valueOf(buildingNum), Long.valueOf(unitId));
                    if (StringUtils.isNotBlank(roomNumber)) {
                        houseList = houseRepository.findByResidenceCommunityIdAndBuildingNumAndUnitAndRoomNumber(communityId, Long.valueOf(buildingNum), Long.valueOf(unitId), roomNumber);
                    }
                }
            }
        }

        switch (scope) { // 账单范围选择[ 1物业、2小区、3楼栋、4单元、5房号]
            case 1:
                Map<Long, Object> tempMap = new HashMap<>();
                for (House house : houseList) {
                    Map<String, Object> map = new HashMap<>();
                    if (tempMap.containsKey(house.getHousePropertyId())) {
                        continue;
                    }
                    map.put("housePropertyId", house.getHousePropertyId());
                    DepartmentHierarchy h = departmentHierarchyRepository.findByOrgId(house.getHousePropertyId());
                    map.put("housePropertyName", h.getName());
                    resultList.add(map);
                    tempMap.put(house.getHousePropertyId(), 1);
                }
                break;
            case 2:
                Map<String, Object> tempMap1 = new HashMap<>();
                for (House house : houseList) {
                    Map<String, Object> map = new HashMap<>();
                    if (tempMap1.containsKey(house.getResidenceCommunityId())) {
                        continue;
                    }
                    map.put("communityId", house.getResidenceCommunityId());
                    Community community = communityRepository.findById(house.getResidenceCommunityId()).get();
                    map.put("communityName", community.getName());
                    resultList.add(map);
                    tempMap1.put(house.getResidenceCommunityId(), 1);
                }
                break;
            case 3:
                Map<String, Object> tempMap2 = new HashMap<>();
                for (House house : houseList) {
                    Map<String, Object> map = new HashMap<>();
                    if (tempMap2.containsKey(house.getResidenceCommunityId() + house.getBuildingNum())) {
                        continue;
                    }
                    map.put("communityId", house.getResidenceCommunityId());
                    Community community = communityRepository.findById(house.getResidenceCommunityId()).get();
                    map.put("communityName", community.getName());

                    map.put("buildingNum", house.getBuildingNum());
                    CommunityBuild build = communityBuildRepository.findById(house.getBuildingNum()).get();
                    map.put("buildingNumName", build.getName());

                    resultList.add(map);
                    tempMap2.put(house.getResidenceCommunityId() + house.getBuildingNum(), 1);
                }
                break;
            case 4:
                Map<String, Object> tempMap3 = new HashMap<>();
                for (House house : houseList) {
                    Map<String, Object> map = new HashMap<>();
                    if (tempMap3.containsKey(house.getResidenceCommunityId() + house.getBuildingNum() + house.getUnit())) {
                        continue;
                    }
                    map.put("communityId", house.getResidenceCommunityId());
                    Community community = communityRepository.findById(house.getResidenceCommunityId()).get();
                    map.put("communityName", community.getName());

                    map.put("buildingNum", house.getBuildingNum());
                    CommunityBuild build = communityBuildRepository.findById(house.getBuildingNum()).get();
                    map.put("buildingNumName", build.getName());

                    map.put("unit", house.getUnit());
                    CommunityBuildUnit unit = communityBuildUnitRepository.findById(house.getUnit()).get();
                    map.put("unitName", unit.getName());

                    resultList.add(map);
                    tempMap3.put(house.getResidenceCommunityId() + house.getBuildingNum() + house.getUnit(), 1);
                }
                break;
            case 5:
                for (House house : houseList) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("communityId", house.getResidenceCommunityId());
                    Community community = communityRepository.findById(house.getResidenceCommunityId()).get();
                    map.put("communityName", community.getName());

                    map.put("buildingNum", house.getBuildingNum());
                    CommunityBuild build = communityBuildRepository.findById(house.getBuildingNum()).get();
                    map.put("buildingNumName", build.getName());

                    map.put("unit", house.getUnit());
                    CommunityBuildUnit unit = communityBuildUnitRepository.findById(house.getUnit()).get();
                    map.put("unitName", unit.getName());

                    map.put("houseId", house.getId());
                    map.put("roomNumber", house.getRoomNumber());
                    map.put("houseNature", house.getHouseNature());
                    if (chargeType == 8 || chargeType == 9) {  // 收费项目(1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金)
                        if (house.getHouseNature().equals(1)) {
                            continue;  // 过滤掉公租房
                        }
                    }
                    resultList.add(map);
                }
                break;
        }

        pageNumber += 1;
        // 分页数据
        List<Map<String, Object>> pageList = new ArrayList<>();
        // 返回结果
        Map<String, Object> resultMap = new HashMap<>();

        Integer count = resultList.size(); // 记录总数
        Integer pageCount = 0; // 页数
        if (count % pageSize == 0) {
            pageCount = count / pageSize;
        } else {
            pageCount = count / pageSize + 1;
        }
        int fromIndex = 0; // 开始索引
        int toIndex = 0; // 结束索引

        if (pageCount.equals(0)) {
            pageCount = 1;
        }

        if (!pageNumber.equals(pageCount)) {
            fromIndex = (pageNumber - 1) * pageSize;
            toIndex = fromIndex + pageSize;
        } else {
            fromIndex = (pageNumber - 1) * pageSize;
            toIndex = count;
        }

        pageList = resultList.subList(fromIndex, toIndex);

        resultMap.put("total", count);
        resultMap.put("data", pageList);

        return ResultBean.successfulResult(resultMap);
    }

    public ResultBean<Object> findCollectionOrg(String accessToken) {
        TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
        if (tokenRedisVo == null) {
            return ResultBean.failedResultOfToken();
        }
        Long enterpriseId = tokenRedisVo.getEnterpriseId();

        DepartmentHierarchy departmentHierarchy = departmentHierarchyRepository.findByOrgId(enterpriseId);
        List<Map<String, Object>> data = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("collectionOrg", departmentHierarchy.getOrgId());
        map.put("collectionOrgName", departmentHierarchy.getName());
        data.add(map);

        String sql = "SELECT org_id AS collectionOrg,NAME AS collectionOrgName \n" +
                "FROM (SELECT t1.parent_id,t1.id,t1.org_id,t1.name,IF(FIND_IN_SET(parent_id, @pids) > 0,@pids := CONCAT(@pids, ',', id),0) AS ischild \n" +
                "FROM (SELECT id,org_id,parent_id,NAME FROM saas_department_hierarchy t ORDER BY parent_id, id) t1,(SELECT @pids := ?) t2)\n" +
                "t3 WHERE ischild != 0";
        List<Map<String, Object>> orgList = jdbcTemplate.queryForList(sql, departmentHierarchy.getId());
        data.addAll(orgList);

        return ResultBean.successfulResult(data);
    }


    // 获得账单范围机构数据  scope: 账单范围选择[ 1物业、2小区、3楼栋、4单元、5房号,6机构，7产权单位 8 物业]
    public ResultBean<Object> billingRange(String accessToken, Integer scope) {
        TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
        if (tokenRedisVo == null) {
            return ResultBean.failedResultOfToken();
        }

        switch (scope) { // 账单范围选择[ 1物业、2小区、3楼栋、4单元、5房号]

            case 6:
                scope = 3;
                break;
            case 7:
                scope = 2;
                break;
            case 8:
                scope = 4;
                break;
        }
        // 新增查询出房东机构下的房产信息 xiaolong 20230315
        Integer scope1 = 0;
        if (scope == 2) {
            scope1 = 8;
        }
        Long enterpriseId = tokenRedisVo.getEnterpriseId();
        List<Map<String, Object>> data = new ArrayList<>();

        String sql = "SELECT a.* FROM  saas_department_hierarchy a\n" +
                "LEFT JOIN saas_department_enterprise_tag_ref b on b.dep_ref_id = a.id \n" +
                "WHERE a.org_id = ?  and (b.tag_id=? OR b.tag_id = ? )and status=1";
        List<DepartmentHierarchy> departmentHierarchyList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(DepartmentHierarchy.class), enterpriseId, scope, scope1);
        if (null != departmentHierarchyList && departmentHierarchyList.size() > 0) {
            Map<String, Object> map = new HashMap<>();
            map.put("collectionOrg", departmentHierarchyList.get(0).getOrgId());
            map.put("collectionOrgName", departmentHierarchyList.get(0).getName());
            data.add(map);
        }

        String sql2 = "SELECT org_id AS collectionOrg,NAME AS collectionOrgName  \n" +
                "FROM (SELECT t1.parent_id,t1.id,t1.org_id,t1.name,IF(FIND_IN_SET(parent_id, @pids) > 0,@pids := CONCAT(@pids, ',', id),0) AS ischild  \n" +
                "FROM (SELECT id,org_id,parent_id,NAME FROM saas_department_hierarchy t ORDER BY parent_id, id) t1,(SELECT @pids := ?) t2) \n" +
                "t3 \n" +
                "LEFT JOIN saas_department_enterprise_tag_ref t4 on t4.dep_ref_id = t3.id\n" +
                "WHERE ischild != 0 and t4.tag_id=?";
        List<Map<String, Object>> orgList = jdbcTemplate.queryForList(sql2, enterpriseId, scope);
        data.addAll(orgList);

        return ResultBean.successfulResult(data);
    }

    // 获得账单范围机构数据  scope: 账单范围选择[ 1物业、2小区、3楼栋、4单元、5房号,6机构，7产权单位 8 物业]
    public ResultBean<Object> companyName(String accessToken) {
        TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
        if (tokenRedisVo == null) {
            return ResultBean.failedResultOfToken();
        }
        List<Map<String, Object>> data = new ArrayList<>();

        List<MatchUserHouse> matchUserHouseList = matchUserHouseRepository.findAll();
        List<String> companyNameList = matchUserHouseList.stream().map(x -> x.getCompanyName()).distinct().collect(Collectors.toList());
        // 遍历循环单位名称
        for (String name : companyNameList) {
            // 判断如果单位名称为空，不存在返回给前端
            if (!(StringUtils.isEmpty(name))) {
                Map<String, Object> map = new HashMap<>();
                map.put("collectionOrg", null);
                map.put("collectionOrgName", name);
                data.add(map);
            }
        }

        return ResultBean.successfulResult(data);
    }


    // 查询账单范围下的房源数据 [scope: 账单范围选择[ 1物业、2小区、3楼栋、4单元、5房号,6机构，7产权单位 8 物业]]  , chargeType :收费项目(1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金)
    public ResultBean<Object> houseInfo(String accessToken, Integer pageNumber, Integer pageSize, Integer scope, Integer chargeType, String communityId, String buildingNum, String unitId, String roomNumber, Long orgId, String companyName) {
        LOG.info("NewPropertyBillService  findByHouseInfo  accessToken={} ", accessToken);
        TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
        if (tokenRedisVo == null) {
            return ResultBean.failedResultOfToken();
        }
        List<HouseInfoVo> houseList = appCommunityService.findCommunitys(accessToken, scope, orgId, communityId, buildingNum, unitId, roomNumber, companyName).getResultData();

        List<Map<String, Object>> resultList = new ArrayList<>();

        ArrayList<CommunitysVO> communityList = new ArrayList<>();

        for (HouseInfoVo house : houseList) {
            Map<String, Object> map = new HashMap<>();
            map.put("communityId", house.getCommunityId());// 小区ID
            map.put("communityName", house.getCommunityName());// 小区名称
            map.put("buildingNum", house.getBuildingNum());// 楼栋ID
            map.put("buildingNumName", house.getBuildingName());// 楼栋名称
            map.put("unit", house.getUnit());// 单元ID
            map.put("unitName", house.getUnitName());// 单元名称
            map.put("houseId", house.getId());// 房屋ID
            map.put("roomNumber", house.getRoomNumber());// 房号名称
            map.put("houseNature", house.getHouseNature());// 房屋类型

            map.put("term", house.getTerm());// 合同期限
            map.put("payType", house.getPayType());// 类型

            if (chargeType == 8 || chargeType == 9) {  // 收费项目(1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金)
                if (ObjectUtil.isNotNull(house.getHouseNature()) && house.getHouseNature().equals(1)) {
                    continue;  // 过滤掉公租房
                }
            }
            CommunitysVO communityVO = new CommunitysVO();
            communityVO.setCommunityId(house.getCommunityId());
            communityVO.setCommunityName(house.getCommunityName());
            communityList.add(communityVO);
            resultList.add(map);
        }
        pageNumber += 1;
        // 分页数据
        List<Map<String, Object>> pageList = new ArrayList<>();
        // 返回结果
        Map<String, Object> resultMap = new HashMap<>();

        Integer count = resultList.size(); // 记录总数
        Integer pageCount = 0; // 页数
        if (count % pageSize == 0) {
            pageCount = count / pageSize;
        } else {
            pageCount = count / pageSize + 1;
        }
        int fromIndex = 0; // 开始索引
        int toIndex = 0; // 结束索引

        if (pageCount.equals(0)) {
            pageCount = 1;
        }

        if (!pageNumber.equals(pageCount)) {
            fromIndex = (pageNumber - 1) * pageSize;
            toIndex = fromIndex + pageSize;
        } else {
            fromIndex = (pageNumber - 1) * pageSize;
            toIndex = count;
        }

        // 修复bug 2409 app生成账单 选择选择四惠小区时，往下拉有时会出现 toIndex = 20
        // 之前没有对数组进行判断
        if (resultList.size() >= toIndex) {
            pageList = resultList.subList(fromIndex, toIndex);
        } else {
            pageList = resultList.subList(fromIndex, resultList.size());
        }

        resultMap.put("total", count);
        resultMap.put("data", pageList);
        resultMap.put("community", communityList);

        return ResultBean.successfulResult(resultMap);
    }


    /**
     * 账单列表-催缴费
     *
     * @param accessToken
     * @param vo          每催缴一次到redis缓存催缴记录设置过期时间为一天 一天不可重复催缴 催缴发送短信 和推送待办事项
     */
    public ResultBean<Object> urgingPayment(String accessToken, UrgingPaymentVo vo) {
        LOG.info("NewPropertyBillService  findByHouseInfo  accessToken={} ", accessToken);
        TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
        List<UrgingPaymentDTO> urgingPayment = vo.getUrgingPayment();
        if (urgingPayment == null || urgingPayment.isEmpty()) {
            return ResultBean.failedResultWithMsg("请选择至少一个账单");
        }
        for (UrgingPaymentDTO dto : urgingPayment) {
            Integer chargeType = dto.getChargeType();

            // 24小时相同订单只能催缴一次
            String value = redisService.gutBillId(dto.getId() + "_" + chargeType);
            if (StringUtils.isNotBlank(value)) {
                LOG.info("催缴费, 24小时内过滤, value={}", value);
                continue;
            }

            String matchUserId = null;
            String houseId = null;
            String cost = null;
            String expenseBillID = null;
            Long id = Long.valueOf(dto.getId());
            if (chargeType == 8 || chargeType == 9) {
                Optional<EstateRentBill> expenseBillOptional = estateRentBillRepository.findById(id);
                if (!expenseBillOptional.isPresent()) {
                    return ResultBean.failedResultWithMsg("账单信息不存在");
                }
                EstateRentBill estateRentBill = expenseBillOptional.get();
                matchUserId = estateRentBill.getMatchUserId();
                houseId = estateRentBill.getHouseId();
                cost = fenToYuan(String.valueOf(estateRentBill.getCost()));
                expenseBillID = String.valueOf(estateRentBill.getId());

            } else {
                Optional<EstateExpenseBill> expenseBillOptional = estateExpenseBillRepository.findById(id);
                if (!expenseBillOptional.isPresent()) {
                    return ResultBean.failedResultWithMsg("账单信息不存在");
                }
                EstateExpenseBill expenseBill = expenseBillOptional.get();
                matchUserId = expenseBill.getMatchUserId();
                houseId = expenseBill.getHouseId();
                cost = fenToYuan(String.valueOf(expenseBill.getCost()));
                expenseBillID = String.valueOf(expenseBill.getId());
            }


            List<String> phoneList = new ArrayList<>();
            List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
            if (communityHouseUserList == null || communityHouseUserList.size() <= 0) {
                return ResultBean.failedResultWithMsg("该房屋账单没有承租人！");
            }

            Long unitLesseeId = houseRepository.findById(houseId).get().getUnitLesseeId();
            if (ObjectUtil.isNull(unitLesseeId)) {
                phoneList.add(communityHouseUserList.get(0).getMobile());
            } else {

                List<CommunityHouseUser> communityHouseUsers = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
                communityHouseUsers.stream().map(CommunityHouseUser::getMobile).forEach(phoneList::add);
            }


//            if (null == matchUserId) {
//                List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
//                if (communityHouseUserList == null || communityHouseUserList.size() <= 0){
//                    return ResultBean.failedResultWithMsg("该房屋账单没有承租人！");
//                }
//                phone=communityHouseUserList.get(0).getMobile();
//
//            }else {
//                AppUser appUser = appUserRepository.findByIdOrEnterpriseUserId(matchUserId, matchUserId);
//
//                if (appUser == null) {
//                    return ResultBean.failedResultWithMsg("承租人不存在");
//                }
//                phone=appUser.getPhone();
//
//            }


            String chargeName = "";
            switch (chargeType) { // 收费项目(1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费 8租金 9押金)

                case 1:
                    chargeName = "水费";
                    break;
                case 2:
                    chargeName = "电费";
                    break;
                case 3:
                    chargeName = "物业费";
                    break;
                case 4:
                    chargeName = "宽带费 ";
                    break;
                case 5:
                    chargeName = "电视费 ";
                    break;
                case 6:
                    chargeName = "燃气费 ";
                    break;
                case 7:
                    chargeName = "暖气费 ";
                    break;
                case 8:
                    chargeName = "租金 ";
                    break;
                case 9:
                    chargeName = "押金 ";
                    break;
            }

            for (String phone : phoneList) {
                // 写入待办事项
                BacklogItem backlogItem = new BacklogItem();
                backlogItem.setHouseId(houseId); // 房id
                backlogItem.setType(40); // 类型：1公租房录入 2智能锁(租金/押金) 3其它费用账单 4资格申请-配租 5备案 6合同到期 13智能锁个人绑定确认 14门锁低电量告警 15门锁离线:
                backlogItem.setTitle("催缴费"); // 标题
                backlogItem.setContent("您的" + chargeName + "账单已欠费，金额为" + cost + "元，为不影响正常使用"); // 内容
                backlogItem.setHandleStatus(0); // 事项处理状态：0未读/未处理 1已读/已处理
                backlogItem.setBusinessStatus("待缴费"); // 业务状态
                backlogItem.setOperatorId(tokenRedisVo.getId()); // 操作人id
                backlogItem.setMatchUserId(matchUserId); // 承租人id
                backlogItem.setPhone(phone); // 接收人手机号
                backlogItem.setCreateTime(new Date()); // 创建时间

                BacklogItem save = backlogItemRepository.save(backlogItem);
                if (chargeType == 8 || chargeType == 9) {
                    BacklogItemPropertyRentBill backlogItemPropertyRentBill = new BacklogItemPropertyRentBill();
                    backlogItemPropertyRentBill.setBacklogItemId(save.getId()); // 待办事项id
                    backlogItemPropertyRentBill.setRentBillId(Long.valueOf(expenseBillID)); // 账单单号
                    backlogItemPropertyRentBill.setMatchUserId(matchUserId); // 承租人id
                    backlogItemPropertyRentBillRepository.save(backlogItemPropertyRentBill);

                } else {
                    SaasBacklogItemBill backlogItemBill = new SaasBacklogItemBill();
                    backlogItemBill.setBacklogItemId(save.getId()); // 待办事项id
                    backlogItemBill.setBillId(expenseBillID); // 账单单号
                    backlogItemBill.setMatchUserId(matchUserId); // 承租人id
                    saasBacklogItemBillRepository.save(backlogItemBill);
                }

                // 发送短信
                if (StringUtils.isNotEmpty(phone)) {
                    smsService.sendTemplateSmsWithData(phone, smsConfig.getPromptTemplateCode(), new String[]{chargeName, cost});
                }
            }



            // 缓存催缴记录
            redisService.putBillId(dto.getId() + "_" + chargeType);
        }

        return ResultBean.successfulResult(null);
    }


    /**
     * 账单生成-立即生成
     *
     * @param accessToken
     * @param ruleId
     * @author qixi
     * @date 2023年3月6日
     */
    @Transactional
    public ResultBean<Object> generateBill(String accessToken, String ruleId) {
        LOG.info("NewPropertyBillService  generateBill  accessToken={},ruleId={}", accessToken, ruleId);
        try {
            TokenRedisVo tokenRedisVo = redisService.findTokenVo(accessToken);
            if (tokenRedisVo == null) {
                return ResultBean.failedResultOfToken();
            }

            if (StringUtils.isEmpty(ruleId)) {
                return ResultBean.failedResultOfParamWithMsg("账单id有误");
            }

            HouseExpenseBillRule rule = houseExpenseBillRuleRepository.findById(ruleId);
            if (rule == null) {
                return ResultBean.failedResultWithMsg("当前账单不存在");
            }

            if (rule.getCreateStatus() == 1) {
                return ResultBean.failedResultWithMsg("当前的账单以生成，请勿重复生成！");
            }
            // 查询收费项目
            HouseExpenseOther expenseOther = houseExpenseOtherRepository.findById(rule.getExpenseId());
            if (expenseOther == null) {
                return ResultBean.failedResultWithMsg("没有收费项目");
            }

            Date startTime = rule.getStartTime();
            Date endTime = rule.getEndTime();
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            Integer chargeType = rule.getChargeType();


            Integer flag = rule.getFlag();
            Integer day = rule.getDay();
            Long collectionOrg = rule.getCollectionOrg();
            // 获取最后生成的账单周期
            if (chargeType != null) {
                if (chargeType != 9 && chargeType != 8) {
                    List<EstateExpenseBill> expenseBills = estateExpenseBillRepository.findByRuleId(rule.getId());
                    if (!expenseBills.isEmpty()) {
                        startTime = expenseBills.get(0).getStartTime();
                        Calendar cal = Calendar.getInstance();
                        cal.setTime(startTime);
                        cal.add(Calendar.MONTH, 1);
                        startTime = df.parse(df.format(cal.getTime()));

                    }
                } else {
                    List<EstateRentBill> estateRentBills = estateRentBillRepository.findByRuleId(rule.getId());
                    if (!estateRentBills.isEmpty()) {
                        startTime = estateRentBills.get(0).getStartTime();
                        Calendar cal = Calendar.getInstance();
                        cal.setTime(startTime);
                        cal.add(Calendar.MONTH, 1);
                        startTime = df.parse(df.format(cal.getTime()));
                    }
                }
            }

            Integer chargeMode = expenseOther.getChargeMode();

            // 拆分时间段
            List<Map<String, String>> dateList = new ArrayList<>();
            Date tempDate = startTime;
            BigDecimal month = new BigDecimal(1);
            if (chargeMode != null) {
                switch (chargeMode) {
                    case 1:
                        dateList = dateList(tempDate, endTime, 1);
                        month = new BigDecimal(1);
                        break;
                    case 2:
                        dateList = dateList(tempDate, endTime, 3);
                        month = new BigDecimal(3);
                        break;
                    case 3:
                        dateList = dateList(tempDate, endTime, 6);
                        month = new BigDecimal(6);
                        break;
                    case 4:
                        dateList = dateList(tempDate, endTime, 12);
                        month = new BigDecimal(12);
                        break;
                }
            } else {
                Map<String, String> map = new HashMap<>();
                map.put("start", df.format(tempDate));
                map.put("end", df.format(endTime));
                dateList.add(map);
            }

            List<HouseExpenseRuleRef> refs = houseExpenseRuleRefRepository.findByRuleId(ruleId);
            if (!refs.isEmpty()) {
                for (HouseExpenseRuleRef ref : refs) {

                    Integer houseNature = ref.getHouseNature();
                    String houseId = ref.getHouseId();
                    Optional<House> byId = houseRepository.findById(houseId);
                    if (!byId.isPresent()) {
                        LOG.warn("当前房屋不存在");
                        continue;
                    }

                    House house = byId.get();
                    for (Map<String, String> m : dateList) {
                        String start = m.get("start");
                        String end = m.get("end");

                        // 获取截止时间
                        Date startTimes = df.parse(start);

                        Integer dateFlag = rule.getDateFlag();    // 时间标志：1开始时间 2结束时间
                        if (dateFlag != null) {
                            if (dateFlag.equals(2)) {
                                startTimes = df.parse(end);
                            }
                        }

                        Date closeTime = null;
                        if (flag.equals(1)) {  // 1前 2后
                            Calendar c = Calendar.getInstance();
                            c.setTime(startTimes);
                            c.add(Calendar.DAY_OF_MONTH, -day);
                            c.set(Calendar.HOUR_OF_DAY, 23);
                            c.set(Calendar.MINUTE, 59);
                            c.set(Calendar.SECOND, 59);
                            // 防止mysql自动加一秒,毫秒设为0
                            c.set(Calendar.MILLISECOND, 0);
                            closeTime = c.getTime();
                        } else {
                            Calendar c = Calendar.getInstance();
                            c.setTime(startTimes);
                            c.add(Calendar.DAY_OF_MONTH, day);
                            c.set(Calendar.HOUR_OF_DAY, 23);
                            c.set(Calendar.MINUTE, 59);
                            c.set(Calendar.SECOND, 59);
                            // 防止mysql自动加一秒,毫秒设为0
                            c.set(Calendar.MILLISECOND, 0);
                            closeTime = c.getTime();
                        }

                        Integer cose = 0;
                        BigDecimal price = new BigDecimal(expenseOther.getPrice());
                        // 计量单位，如：月/度/平方
                        String unit = expenseOther.getUnit();
                        BigDecimal temp = null;
                        switch (chargeType) {  // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费
                            case 3:
                                // 物业费 = 面积 * 单价 * 天数
                                BigDecimal area = house.getArea();
                                temp = area.multiply(price).multiply(month);
                                cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                break;
                            case 4:
                                // 宽带费 = 月份 * 单价
                                temp = month.multiply(price);
                                cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                break;
                            case 5:
                                // 电视费 = 月份 * 单价
                                temp = month.multiply(price);
                                cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                break;
                            case 7:
                                // 暖气费 = 面积 * 单价 * 日期
                                BigDecimal area1 = house.getArea();
                                temp = area1.multiply(price).multiply(month);
                                cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                break;
                            case 8:
                                // 租金  单价 = 面积 * 单价 * 天数
                                if (expenseOther.getChargeStatus() == 0) {
                                    BigDecimal area2 = house.getArea();
                                    temp = area2.multiply(price).multiply(month);
                                    cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                } else {
                                    // 总价 价格 * 天数
                                    temp = price.multiply(month);
                                    cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                }
                                break;
                            case 9:
                                // 押金 = 单价(一次性)
                                temp = price;
                                cose = Integer.valueOf(temp.setScale(0, BigDecimal.ROUND_HALF_UP).toString());
                                break;
                        }


                        // List<CommunityHouseUser> communityHouseUserList = communityHouseUserRepository.findByCommunityHouseIdAndStatusAndType(houseId, 1, 1);
                        // String matchUserId = null;
                        // if (communityHouseUserList.size() > 0) {
                        //     matchUserId = communityHouseUserList.get(0).getUserId();
                        // }
                        //
                        // if (houseNature != null && houseNature.equals(1)) {  // 公租房
                        //     List<String> hlist = new ArrayList<>();
                        //     hlist.add(houseId);
                        //     List<HouseMatchUser> hmUserList = houseMatchUserRepository.findByHouseIdInAndStatus(hlist, 1);
                        //     if (hmUserList.size() > 0) {
                        //         matchUserId = hmUserList.get(0).getMatchUserId();
                        //     }
                        // }

                        String matchUserId = null;
                        List<MatchUserHouse> byHouseId = matchUserHouseRepository.findByHouseId(houseId);
                        if (!byHouseId.isEmpty()) {
                            String matchUserStockId = byHouseId.get(0).getMatchUserStockId();
                            //	根据承租人和房产的承租人id查询承认人表的房产承租人id
                            Optional<MatchUser> matchUserRepositoryById = matchUserRepository.findById(Long.parseLong(matchUserStockId));
                            if (matchUserRepositoryById.isPresent()) {
                                // 产权下的用户承租人id
                                MatchUser byMatchUserId = matchUserRepositoryById.get();
                                // 产权下的用户承租人id
                                matchUserId = byMatchUserId.getMatchUserId();
                            }
                        }

                        // 其他费用账单
                        if (chargeType != 8 && chargeType != 9) {
                            // 生成账单
                            EstateExpenseBill estateExpenseBill = new EstateExpenseBill();

                            estateExpenseBill.setHouseId(houseId);
                            estateExpenseBill.setChargeType(chargeType);
                            estateExpenseBill.setCommunityId(house.getResidenceCommunityId());
                            estateExpenseBill.setBuildingNum(house.getBuildingNum());
                            estateExpenseBill.setUnit(house.getUnit());
                            if (collectionOrg == null) {
                                estateExpenseBill.setOrgId(house.getHousePropertyId());
                            } else {
                                estateExpenseBill.setOrgId(collectionOrg);
                            }
                            estateExpenseBill.setPaymentStatus(0);
                            estateExpenseBill.setRoomNumber(house.getRoomNumber());
                            estateExpenseBill.setMatchUserId(matchUserId);
                            estateExpenseBill.setCost(cose);
                            estateExpenseBill.setSurplusCost(cose);
                            estateExpenseBill.setMeasureUnit(unit);
                            estateExpenseBill.setStartTime(df.parse(start));
                            estateExpenseBill.setEndTime(df.parse(end));
                            estateExpenseBill.setCreateTime(new Date());
                            estateExpenseBill.setAuditStatus(0);      //'审核状态：0未审核 1已审核'
                            estateExpenseBill.setBillType(1);
                            estateExpenseBill.setShouldPayTime(closeTime);
                            estateExpenseBill.setRuleId(ruleId);
                            estateExpenseBill.setAdjustStatus(0);
                            EstateExpenseBill save = estateExpenseBillRepository.save(estateExpenseBill);


                            // 账单用量费用
                            EstateExpenseBillDetail estateExpenseBillDetail = new EstateExpenseBillDetail();
                            List<EstateExpenseBill> andHouseId = estateExpenseBillRepository.findByRuleIdAndHouseIdAndChargeType(ruleId, houseId, chargeType);
                            if (!andHouseId.isEmpty()) {
                                if (andHouseId.size() >= 2) {
                                    // 获取上个账单起止数
                                    estateExpenseBillDetail = estateExpenseBillDetailRepository.findByExpenseBillId(andHouseId.get(andHouseId.size() - 2).getId());
                                } else {
                                    // 获取上个账单起止数
                                    estateExpenseBillDetail = estateExpenseBillDetailRepository.findByExpenseBillId(andHouseId.get(0).getId());
                                }
                            }
                            if (andHouseId.size() <= 1 && estateExpenseBillDetail == null) {
                                EstateExpenseBillDetail detail = new EstateExpenseBillDetail();
                                detail.setExpenseBillId(save.getId());
                                detail.setChargeType(save.getChargeType());
                                switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 1:
                                        detail.setWaterStartNum(0);
                                        detail.setWaterEndNum(0);
                                        detail.setWaterUsage(null);
                                        detail.setWaterUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 2:
                                        detail.setElectricStartNum(0);
                                        detail.setElectricEndNum(0);
                                        detail.setElectricUsage(null);
                                        detail.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 3:
                                        detail.setPropertyFee(save.getCost());
                                        break;
                                    case 4:
                                        detail.setBroadBandCharges(save.getCost());
                                        break;
                                    case 5:
                                        detail.setTvFee(save.getCost());
                                        break;
                                    case 6:
                                        detail.setGasStartNum(0);
                                        detail.setGasEndNum(0);
                                        detail.setGasUsage(null);
                                        detail.setGasUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 7:
                                        detail.setHeatingBill(save.getCost());
                                        break;
                                }

                                estateExpenseBillDetailRepository.save(detail);
                            }
                            if (!andHouseId.isEmpty() && estateExpenseBillDetail != null) {

                                EstateExpenseBillDetail estateExpenseBill1 = new EstateExpenseBillDetail();
                                estateExpenseBill1.setExpenseBillId(save.getId());
                                estateExpenseBill1.setChargeType(save.getChargeType());
                                switch (save.getChargeType()) {   // 1水费 2电费 3物业费 4宽带费 5电视费 6煤气费 7暖气费

                                    case 1:
                                        estateExpenseBill1.setWaterStartNum(estateExpenseBillDetail.getWaterEndNum());
                                        estateExpenseBill1.setWaterEndNum(0);
                                        estateExpenseBill1.setWaterUsage(null);
                                        estateExpenseBill1.setWaterUnitPrice(Integer.valueOf(price.toString()));

                                        break;
                                    case 2:
                                        estateExpenseBill1.setElectricStartNum(estateExpenseBillDetail.getElectricEndNum());
                                        estateExpenseBill1.setElectricEndNum(0);
                                        estateExpenseBill1.setElectricUsage(null);
                                        estateExpenseBill1.setElectricUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 3:
                                        estateExpenseBill1.setPropertyFee(save.getCost());
                                        break;
                                    case 4:
                                        estateExpenseBill1.setBroadBandCharges(save.getCost());
                                        break;
                                    case 5:
                                        estateExpenseBill1.setTvFee(save.getCost());
                                        break;
                                    case 6:
                                        estateExpenseBill1.setGasStartNum(estateExpenseBillDetail.getGasEndNum());
                                        estateExpenseBill1.setGasEndNum(0);
                                        estateExpenseBill1.setGasUsage(null);
                                        estateExpenseBill1.setGasUnitPrice(Integer.valueOf(price.toString()));
                                        break;
                                    case 7:
                                        estateExpenseBill1.setHeatingBill(save.getCost());
                                        break;
                                }

                                estateExpenseBillDetailRepository.save(estateExpenseBill1);
                            }

                        } else {
                            // 租金押金
                            // 收费项目:8租金 9押金
                            Integer billChargeType = 2;
                            if (chargeType == 8) {
                                billChargeType = 1;
                            }
                            // 生成账单
                            EstateRentBill estateRentBill = new EstateRentBill();
                            estateRentBill.setHouseId(houseId);
                            estateRentBill.setChargeType(billChargeType);
                            estateRentBill.setCommunityId(house.getResidenceCommunityId());
                            estateRentBill.setBuildingNum(house.getBuildingNum());
                            estateRentBill.setUnit(house.getUnit());
                            if (collectionOrg == null) {
                                estateRentBill.setOrgId(house.getHousePropertyId());
                            } else {
                                estateRentBill.setOrgId(collectionOrg);
                            }
                            estateRentBill.setPaymentStatus(0);
                            estateRentBill.setRoomNumber(house.getRoomNumber());
                            estateRentBill.setMatchUserId(matchUserId);
                            estateRentBill.setCost(cose);
                            estateRentBill.setSurplusCost(cose);
                            estateRentBill.setMeasureUnit(unit);
                            estateRentBill.setStartTime(df.parse(start));
                            estateRentBill.setEndTime(df.parse(end));
                            estateRentBill.setShouldPayTime(closeTime);
                            estateRentBill.setCreateTime(new Date());
                            estateRentBill.setAuditStatus(0);     // 审核状态：0未审核 1已审核
                            estateRentBill.setRuleId(ruleId);
                            estateRentBill.setAdjustStatus(0);
                            EstateRentBill save = estateRentBillRepository.save(estateRentBill);
                        }
                    }
                }
            }
            // 0未生成 1已生成
            rule.setCreateStatus(1);
            houseExpenseBillRuleRepository.save(rule);

            return ResultBean.successfulResult("账单生成成功");
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return ResultBean.failedResultOfException();
        }
    }

    /*
     *分转换为元
     */
    private String fenToYuan(String amount) {
        NumberFormat format = NumberFormat.getInstance();
        try {
            Number number = format.parse(amount);
            double temp = number.doubleValue() / 100.0;
            format.setGroupingUsed(false);
            // 设置返回的小数部分所允许的最大位数
            format.setMaximumFractionDigits(2);
            amount = format.format(temp);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return amount;
    }

    public List<Map<String, String>> dateList(Date tempDate, Date endDate, int month) {

        List<Map<String, String>> dateList = new ArrayList<>();
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        Calendar startCal = Calendar.getInstance();
        Calendar endCal = Calendar.getInstance();

        for (; ; ) {
            Map<String, String> map = new HashMap<>();
            startCal.setTime(tempDate);
            String start = df.format(startCal.getTime());
            map.put("start", start);
            startCal.add(Calendar.MONTH, month);// 下一个开始日期

            endCal.setTime(startCal.getTime());
            endCal.add(Calendar.DAY_OF_MONTH, -1);
            Date temEnd = endCal.getTime();
            // 拆分后的结束时间 > 周期结束时间
            if (temEnd.getTime() >= endDate.getTime()) {
                map.put("end", df.format(endDate));
                dateList.add(map);
                break;
            } else {
                tempDate = startCal.getTime();
                map.put("end", df.format(temEnd));
                dateList.add(map);
            }
        }

        return dateList;
    }


}
